在前文物件導向的特性中,提到物件導向設計本身具有封裝、繼承、多型、抽象這些特性。
知道物件導向的特性,就可以寫出具備閱讀性、維謢性、擴充性的程式碼?答案是肯定的,但卻非常的困難。之所以困難,常見的因素列表如下。
當然還有許多因素,是筆者沒有想到或是沒有列出來的。
使用物件導向開發軟體的過程中,如果能配上Robert C. Martin提出的物件導向設計的五個原則(SOLID):單一職責、開放封閉、里氏替換、接口隔離以及依賴反轉。這樣會更容易開發出易維護與擴展的系統。
每個物件,不管是類別、函數,負責的功能,都應該只做一件事。
對函數而言,一個函數內,同時做了兩件以上的事情。當發生錯誤時,很難快速定位錯誤的原因。另外,也容易間接導至程式碼的可閱讀性降低。
藉由增加新的程式碼來擴充系統的功能,而不是藉由修改原本已經存在的程式碼來擴充系統的功能。
當需求有異動時,要如何在不變動現在正常運行的程式碼,藉由繼承、相依性注入等方式,增加新的程式碼,以實作新的需求。
假若為了新需求,去修改了原本的程式中的某一個函數,可能會造成其他呼叫使用該函數的的功能,出現非預期的錯誤。
Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it.
簡單來說,當實作繼承了 interface 或 base-class的 sub-class,那麼在程式中,只要出現該 interface 或 base-class 的部份,都可以用 sub-class 替換。
針對不同需求的用戶,開放其對應需求的介面,提拱使用。可避免不相關的需求介面異動,造成被強迫一同面對異動的情況。
A. High-level modules should not depend on low-level modules. Both should depend on abstractions.
B. Abstractions should not depend on details. Details should depend on abstractions.
當 A 模組在內部使用 B 模組的情況下,我們稱 A 為高階模組,B 為低階模組。高階模組不應該依賴於低階模組,兩者都該依賴抽象介面。
在後文從被動變主動—依賴反轉,針對這個主題,特別的提出來討論。
不知道各位看倌有沒有發現,SOLID 的設計原則,都是提供軟體更大的需求修改的空間。
要特別提醒的是,符合 SOLID 的開發方式,雖然較易維護與擴展。但就實務面而言,有時,必需考量使用 SOLID 額外帶來的開發時間,是否是開發期程所能承受的。